package main

import (
	"errors"
	"fmt"
	"strings"
)

func main() {
	// ==========================================
	// 函数声明和调用
	// ==========================================

	// 调用基本函数
	sayHello()

	// 调用带参数的函数
	greet("小明")

	// 调用带返回值的函数
	sum := add(5, 3)
	fmt.Printf("5 + 3 = %d\n", sum)

	// ==========================================
	// 多返回值
	// ==========================================

	// 调用返回多个值的函数
	length, width := getDimensions()
	fmt.Printf("长方形的长度是 %d，宽度是 %d\n", length, width)

	// 忽略某个返回值（使用_）
	area, _ := calculateArea(5, 3)
	fmt.Printf("面积是 %d\n", area)

	// 错误处理模式
	result, err := divide(10, 2)
	if err != nil {
		fmt.Println("错误:", err)
	} else {
		fmt.Printf("10 / 2 = %.2f\n", result)
	}

	result, err = divide(10, 0)
	if err != nil {
		fmt.Println("错误:", err)
	} else {
		fmt.Printf("10 / 0 = %.2f\n", result)
	}

	// ==========================================
	// 命名返回值
	// ==========================================

	// 调用使用命名返回值的函数
	perimeter, area := rectangleInfo(5, 3)
	fmt.Printf("矩形的周长是 %d，面积是 %d\n", perimeter, area)

	// ==========================================
	// 可变参数函数
	// ==========================================

	// 调用可变参数函数
	total := sumNumbers(1, 2, 3, 4, 5)
	fmt.Printf("1 + 2 + 3 + 4 + 5 = %d\n", total)

	// 传递切片给可变参数函数
	numbers := []int{10, 20, 30, 40, 50}
	total = sumNumbers(numbers...) // 注意...语法
	fmt.Printf("10 + 20 + 30 + 40 + 50 = %d\n", total)

	// 调用混合参数的可变参数函数
	joinedString := joinWithSeparator("-", "Go", "is", "awesome")
	fmt.Println(joinedString)

	// ==========================================
	// 匿名函数和闭包
	// ==========================================

	// 定义并立即调用匿名函数
	func() {
		fmt.Println("这是一个匿名函数")
	}()

	// 带参数的匿名函数
	func(name string) {
		fmt.Printf("你好，%s\n", name)
	}("小红")

	// 将匿名函数赋值给变量
	square := func(x int) int {
		return x * x
	}
	fmt.Printf("5的平方是 %d\n", square(5))

	// 闭包：函数可以访问其外部作用域的变量
	counter := createCounter()
	fmt.Printf("计数: %d\n", counter()) // 1
	fmt.Printf("计数: %d\n", counter()) // 2
	fmt.Printf("计数: %d\n", counter()) // 3

	// 另一个闭包示例
	adder := createAdder(10)
	fmt.Printf("10 + 5 = %d\n", adder(5))
	fmt.Printf("10 + 15 = %d\n", adder(15))

	// ==========================================
	// 函数作为参数和返回值
	// ==========================================

	// 函数作为参数
	result1 := calculate(5, 3, add)
	fmt.Printf("5 + 3 = %d\n", result1)

	result2 := calculate(5, 3, subtract)
	fmt.Printf("5 - 3 = %d\n", result2)

	// 函数作为返回值
	doubler := createMultiplier(2)
	tripler := createMultiplier(3)

	fmt.Printf("5 × 2 = %d\n", doubler(5))
	fmt.Printf("5 × 3 = %d\n", tripler(5))

	// ==========================================
	// 递归函数
	// ==========================================

	// 计算阶乘
	fmt.Printf("5! = %d\n", factorial(5))

	// 计算斐波那契数列
	fmt.Printf("斐波那契数列第10项 = %d\n", fibonacci(10))

	// ==========================================
	// defer语句
	// ==========================================

	// defer语句会在函数返回前执行
	deferExample()

	// 多个defer语句按LIFO顺序执行（后进先出）
	multipleDefers()

	// defer与匿名函数结合
	name := "世界"
	defer func() {
		fmt.Printf("再见，%s\n", name)
	}()
	name = "Go" // 修改name的值
	fmt.Printf("你好，%s\n", name)
	// 当defer执行时，会打印"再见，Go"而不是"再见，世界"

	// ==========================================
	// 方法（在结构体上定义的函数）
	// ==========================================

	// 创建一个矩形
	rect := Rectangle{Width: 10, Height: 5}

	// 调用值接收者方法
	fmt.Printf("矩形面积: %d\n", rect.Area())
	fmt.Printf("矩形周长: %d\n", rect.Perimeter())

	// 调用指针接收者方法
	fmt.Printf("缩放前的矩形: %+v\n", rect)
	rect.Scale(2)
	fmt.Printf("缩放后的矩形: %+v\n", rect)

	// ==========================================
	// 练习
	// ==========================================

	// 1. 编写一个函数，接受一个字符串参数，返回该字符串的反转形式

	// 2. 编写一个函数，接受任意数量的整数，返回它们的平均值

	// 3. 创建一个闭包，实现一个能记住最大值的函数

	// 4. 编写一个递归函数，计算给定数字的所有数字之和
	//    例如：sumDigits(123) 应该返回 1+2+3=6

	// 5. 定义一个结构体和一些方法，实现简单的银行账户功能
	//    （存款、取款、查询余额）
}

// ==========================================
// 基本函数
// ==========================================

// 无参数无返回值的函数
func sayHello() {
	fmt.Println("Hello, Go!")
}

// 带参数的函数
func greet(name string) {
	fmt.Printf("你好，%s！\n", name)
}

// 带返回值的函数
func add(a, b int) int {
	return a + b
}

// ==========================================
// 多返回值
// ==========================================

// 返回多个值的函数
func getDimensions() (int, int) {
	return 10, 5
}

// 返回多个命名值的函数
func calculateArea(length, width int) (int, int) {
	area := length * width
	perimeter := 2 * (length + width)
	return area, perimeter
}

// 返回值与错误
func divide(a, b float64) (float64, error) {
	if b == 0 {
		return 0, errors.New("除数不能为零")
	}
	return a / b, nil
}

// ==========================================
// 命名返回值
// ==========================================

// 使用命名返回值的函数
func rectangleInfo(length, width int) (perimeter int, area int) {
	perimeter = 2 * (length + width)
	area = length * width
	return // 裸返回，会自动返回命名的返回值
}

// ==========================================
// 可变参数函数
// ==========================================

// 可变参数函数
func sumNumbers(numbers ...int) int {
	total := 0
	for _, num := range numbers {
		total += num
	}
	return total
}

// 混合普通参数和可变参数
func joinWithSeparator(separator string, parts ...string) string {
	return strings.Join(parts, separator)
}

// ==========================================
// 闭包
// ==========================================

// 返回一个闭包的函数
func createCounter() func() int {
	count := 0
	return func() int {
		count++
		return count
	}
}

// 带参数的闭包
func createAdder(base int) func(int) int {
	return func(x int) int {
		return base + x
	}
}

// ==========================================
// 函数作为参数和返回值
// ==========================================

// 定义函数类型
type MathFunc func(int, int) int

// 函数作为参数
func calculate(a, b int, operation MathFunc) int {
	return operation(a, b)
}

// 另一个函数，用于作为参数传递
func subtract(a, b int) int {
	return a - b
}

// 返回函数的函数
func createMultiplier(factor int) func(int) int {
	return func(x int) int {
		return x * factor
	}
}

// ==========================================
// 递归函数
// ==========================================

// 递归计算阶乘
func factorial(n int) int {
	if n <= 1 {
		return 1
	}
	return n * factorial(n-1)
}

// 递归计算斐波那契数列
func fibonacci(n int) int {
	if n <= 1 {
		return n
	}
	return fibonacci(n-1) + fibonacci(n-2)
}

// ==========================================
// defer示例
// ==========================================

// defer示例函数
func deferExample() {
	fmt.Println("函数开始")
	defer fmt.Println("函数结束") // 将在函数返回前执行

	fmt.Println("函数中间部分")
}

// 多个defer示例
func multipleDefers() {
	fmt.Println("开始执行多个defer")

	for i := 0; i < 3; i++ {
		defer fmt.Printf("defer %d\n", i)
	}

	fmt.Println("函数主体结束")
}

// ==========================================
// 方法（结构体上的函数）
// ==========================================

// 定义一个矩形结构体
type Rectangle struct {
	Width  int
	Height int
}

// 值接收者方法
func (r Rectangle) Area() int {
	return r.Width * r.Height
}

// 值接收者方法
func (r Rectangle) Perimeter() int {
	return 2 * (r.Width + r.Height)
}

// 指针接收者方法（可以修改接收者）
func (r *Rectangle) Scale(factor int) {
	r.Width *= factor
	r.Height *= factor
}
